// TODO: 竞态?
if (typeof Promise === 'undefined') {

    // all 和 race 的 finally, 是否等待全部执行完成
    window.PROMISE_EXECALL = false;

    // 兼容支持 es5+ 的浏览器
    console.info('Use Promise Compatible.');

    /**
     * Promise 普通调用支持多参数 resolve, reject
     * @param   executor    {Function}
     * */
    window.Promise = function (executor) {

        var isExec = false;

        var resolveCallBack = null;
        var rejectCallBack = null;
        var finalCallBack = null;

        var isFinal = true;
        var final = function (finalVal) {
            isFinal = finalVal;
            if (isExec){
                finalCallBack && finalCallBack();
            }
        };

        var resolveData = null;
        var resolve = function () {
            if (isExec) return;
            if (resolveCallBack){
                resolveCallBack.apply(null, arguments.valueOf());
                isFinal && finalCallBack && finalCallBack();
            } else {
                resolveData = arguments.valueOf();
            }
            isExec = !isExec;
        };

        var rejectData = null;
        var reject = function () {
            if (isExec) return;
            if (rejectCallBack){
                rejectCallBack.apply(null, arguments.valueOf());
                isFinal && finalCallBack && finalCallBack();
            } else {
                rejectData = arguments.valueOf();
            }
            isExec = !isExec;
        };

        /**
         * @param   func    {Function}
         * @return  {Promise}
         * */
        this.then = function (func) {
            if (resolveData) {
                func.apply(null, resolveData);
            }else{
                resolveCallBack = func;
            }
            return this;
        };

        /**
         * @param   func    {Function}
         * @return  {Promise}
         * */
        this.catch = function (func) {
            if (rejectData) {
                func.apply(null, rejectData);
            }else{
                rejectCallBack = func;
            }
            return this;
        };

        /**
         * 默认添加了延时等待, 可支持先 resolve, reject, 后 final
         * @param   func    {Function}
         * @return  {Promise}
         * */
        this.finally = function (func) {
            if (isExec && isFinal) {
                func();
            }else{
                finalCallBack = func;
            }
            return this;
        };

        executor(resolve, reject, final);
    };

    if (typeof window.Promise.__proto__ === 'object'){
        /**
         * 仅支持单个参数 resolve, reject, 保持一致性
         * @param   executors   {Array}
         * */
        window.Promise.__proto__.all = function (executors) {
            return new Promise(function(resolve, reject, final) {
                final(!PROMISE_EXECALL);
                var resolveResult = [];
                var rejectResult = [];
                var processNum = 0;
                for (var i = 0; i < executors.length; i++) {
                    (function (idx){
                        executors[idx].then(function () {
                            resolveResult.push(arguments[0]);
                            if (++processNum === executors.length){
                                if (rejectResult.length !== 0){
                                    reject.apply(null, rejectResult);
                                }else{
                                    resolve.apply(null, resolveResult);
                                }
                                PROMISE_EXECALL && final(true);
                            }
                        }).catch(function () {
                            rejectResult.push(arguments[0]);

                            // TODO: 看个人习惯, EcmaScript 只要有 reject 的直接全部 reject 掉
                            reject.apply(null, rejectResult);

                            if (++processNum === executors.length){
                                // reject.apply(null, rejectResult);
                                PROMISE_EXECALL && final(true);
                            }
                        });
                    })(i);
                }
            });
        };

        /**
         * 仅支持单个参数 resolve, reject, 保持一致性
         * @param   executors   {Array}
         * */
        window.Promise.__proto__.race = function (executors) {
            return new Promise(function(resolve, reject, final) {
                final(!PROMISE_EXECALL);
                var processNum = 0;
                for (var i = 0; i < executors.length; i++) {
                    (function (idx){
                        executors[idx].then(function () {
                            resolve(arguments[0]);
                            if (++processNum === executors.length){
                                PROMISE_EXECALL && final(true);
                            }
                        }).catch(function () {
                            reject(arguments[0]);
                            if (++processNum === executors.length){
                                PROMISE_EXECALL && final(true);
                            }
                        });
                    })(i);
                }
            });
        };
    }else{  // ie11以下
        /**
         * 仅支持单个参数 resolve, reject, 保持一致性
         * @param   executors   {Array}
         * */
        window.Promise.all = function (executors) {
            return new Promise(function(resolve, reject, final) {
                final(!PROMISE_EXECALL);
                var resolveResult = [];
                var rejectResult = [];
                var processNum = 0;
                for (var i = 0; i < executors.length; i++) {
                    (function (idx){
                        executors[idx].then(function () {
                            resolveResult.push(arguments[0]);
                            if (++processNum === executors.length){
                                if (rejectResult.length !== 0){
                                    reject.apply(null, rejectResult);
                                }else{
                                    resolve.apply(null, resolveResult);
                                }
                                PROMISE_EXECALL && final(true);
                            }
                        }).catch(function () {
                            rejectResult.push(arguments[0]);

                            // TODO: 看个人习惯, EcmaScript 只要有 reject 的直接全部 reject 掉
                            reject.apply(null, rejectResult);

                            if (++processNum === executors.length){
                                // reject.apply(null, rejectResult);
                                PROMISE_EXECALL && final(true);
                            }
                        });
                    })(i);
                }
            });
        };

        /**
         * 仅支持单个参数 resolve, reject, 保持一致性
         * @param   executors   {Array}
         * */
        window.Promise.race = function (executors) {
            return new Promise(function(resolve, reject, final) {
                final(!PROMISE_EXECALL);
                var processNum = 0;
                for (var i = 0; i < executors.length; i++) {
                    (function (idx){
                        executors[idx].then(function () {
                            resolve(arguments[0]);
                            if (++processNum === executors.length){
                                PROMISE_EXECALL && final(true);
                            }
                        }).catch(function () {
                            reject(arguments[0]);
                            if (++processNum === executors.length){
                                PROMISE_EXECALL && final(true);
                            }
                        });
                    })(i);
                }
            });
        };
    }

}
